Skip to content

feat(shadcn): #54 rebuild Bottom nav, remove daisyUI and dead MUI deps#61

Merged
fray-cloud merged 7 commits into
devfrom
shadcn/54-finalize
Apr 13, 2026
Merged

feat(shadcn): #54 rebuild Bottom nav, remove daisyUI and dead MUI deps#61
fray-cloud merged 7 commits into
devfrom
shadcn/54-finalize

Conversation

@fray-cloud

@fray-cloud fray-cloud commented Apr 13, 2026

Copy link
Copy Markdown
Owner

Summary

Stacked on #60. Closes the #8 chain.

Bottom.tsx rebuilt

  • daisyUI btm-nav btm-nav-xs + nested <button><a> → plain Tailwind fixed bottom nav:
    fixed inset-x-0 bottom-0 h-12 flex border-t border-border bg-background
  • Each item is a real <button type="button"> with aria-label (no more anchor-in-button nesting); active state swaps text-primary vs text-muted-foreground
  • react-icons preserved; layout still fires router.push

Tailwind

Dependency purge

  • daisyui
  • @mui/joy, @mui/icons-material, @mui/x-date-pickers — all zero imports in apps/web/src (grep verified)
  • @emotion/react, @emotion/styled — pulled only by MUI; framer-motion has its own emotion vendoring so dropping these is safe

Closes #54. Parent #8 closes on merge.

Test plan

  • npx nx affected -t lint test build --exclude web-e2e green
  • rg "bg-neutral(?![-\w])|text-neutral-content|bg-base-\d|text-base-content|btm-nav|navbar|btn-ghost|btn-link|btn-primary|btn-neutral|card-body|card-title|select-bordered|menu-|daisyui" apps/web → zero matches (outside .next/)
  • grep -nE "daisyui|@mui/|@emotion/" package.json → zero

🤖 Generated with Claude Code

Summary by Sourcery

Refactor the web app UI away from DaisyUI/MUI to a Shadcn/Radix-based Tailwind setup, rebuilding navigation and shared components on the new design system.

New Features:

  • Introduce shared Shadcn-style UI primitives (button, card, avatar, progress, skeleton) with a Tailwind-based design system.
  • Add a global Tailwind color and radius theme with class-based dark mode support.

Bug Fixes:

  • Improve bottom navigation semantics by replacing nested anchor-in-button markup with accessible button-based navigation.

Enhancements:

  • Rebuild the bottom navigation, header, and several search/home views to use the new UI primitives and Tailwind utility classes instead of DaisyUI components.
  • Introduce a shared cn utility for composing Tailwind class names and simplify styling across components.
  • Update loading states in list and count views to use skeleton and progress components for more consistent UX.

Build:

  • Update Tailwind configuration to remove DaisyUI, register tailwindcss-animate, and wire theme tokens to CSS variables.

Chores:

  • Remove unused DaisyUI and MUI-related dependencies from the project and add supporting Radix/classname libraries.
  • Disable sidebar exports from the new-component index and enable Nx analytics.

Handcrafted shadcn init to preserve the front/* alias and Nx layout.
Scaffolding only — no call-site swaps; daisyUI plugin remains active.

- apps/web/components.json — shadcn schema 1, style default, rsc true,
  baseColor neutral, cssVariables, aliases mapped onto front/*
  (components → front/new-component, ui → front/new-component/ui,
   utils → front/lib/utils, lib → front/lib, hooks → front/hooks),
  iconLibrary lucide
- apps/web/src/lib/utils.ts — cn helper (clsx + tailwind-merge)
- apps/web/src/new-component/ui/ directory created (empty; #49 fills)
- apps/web/tailwind.config.js — darkMode ['class'], theme.extend.colors
  wired to hsl(var(--*)) shadcn tokens, theme.extend.borderRadius,
  plugins keep `require('daisyui')` and add `tailwindcss-animate`
- apps/web/app/globals.css — :root + .dark CSS variables under
  @layer base
- package.json — class-variance-authority, clsx, tailwind-merge,
  tailwindcss-animate, lucide-react added

- nx affected -t lint test build --exclude web-e2e green
  (4 projects, 10 tasks)
- daisyUI classes still render identically (coexistence by design
  through #54)

Refs #48
Five shadcn/ui components written directly into
apps/web/src/new-component/ui/ to match the aliases configured in
#48. Standard shadcn default-style implementations using cn(),
class-variance-authority (button only), and Radix primitives for
Avatar and Progress. No call-site swaps — files are unreferenced
until #50#54 consume them.

- button.tsx — variants (default/destructive/outline/secondary/ghost/
  link), sizes (default/sm/lg/icon), asChild via @radix-ui/react-slot
- card.tsx — Card + CardHeader/Title/Description/Content/Footer
- skeleton.tsx — animated muted placeholder
- avatar.tsx — Radix Avatar/Image/Fallback ("use client")
- progress.tsx — Radix Progress with translate-based indicator
  ("use client")
- package.json — @radix-ui/react-slot, @radix-ui/react-avatar,
  @radix-ui/react-progress added

- nx affected -t lint test build --exclude web-e2e green

Refs #49
…50)

Header:
- Drops daisyUI navbar/bg-neutral/text-neutral-content/btn-ghost and
  rebuilds as a plain Tailwind flex row using shadcn Button
  variant="ghost" for the title link
- bg-neutral-900 / text-neutral-100 token pair preserves the dark
  contrast originally supplied by daisyUI's neutral theme tokens

Sidebar:
- Deleted. The component was pulled only via the new-component/
  barrel export and rendered nowhere (no consumers after the
  catch-all bridge and SiteRouter were removed in #35).
- new-component/index.ts drops `export * from './sidebar'`.

- nx affected -t lint test build --exclude web-e2e green
- daisyUI plugin still present; coexists with shadcn through #54

Refs #50
Count.tsx:
- daisyUI `avatar` + nested `div.skeleton` → shadcn Avatar/AvatarImage
  and Skeleton. Loading state is now an explicit Skeleton branch
  instead of a class toggle, so there's no more empty .avatar box
  while loading.
- The two text rows (name, totalCount) likewise use Skeleton during
  isLoading.
- "use client" added (was missing; Count uses hooks).

Contents.tsx:
- `<button className="btn btn-link btn-primary">` → shadcn
  <Button variant="link">. router.push wiring unchanged.

- nx affected -t lint test build --exclude web-e2e green
- daisyUI plugin still present

Refs #51
AnimalCard.tsx:
- daisyUI `card bg-base-100 shadow-xl` + `card-body` → shadcn
  Card + CardContent
- `"use client"` added (was missing; useLike is a Zustand hook)
- Inner `<table className="table table-sm">` rewritten without
  daisyUI table classes — plain <table> with Tailwind padding/
  font utilities

SearchView.tsx:
- react-infinite-scroller loader `<progress className="progress"/>`
  → shadcn <Progress className="h-2" />

Form.tsx:
- Submit `<button className="btn btn-sm">` → shadcn
  <Button size="sm" type="submit">

- nx affected -t lint test build --exclude web-e2e green
- daisyUI plugin still present

Refs #52
…#53)

Scope-adjusted from "Radix Select + rhf Controller" to Tailwind-styled
native select while preserving the rhf `register` flow. Reason:
Radix Select rejects empty-string SelectItem values, and every init*
row (initSido, initSigungu, initShelter, initKind, Upkinds[0]) uses
`''` as the "모두" sentinel. Switching to Radix would have required
patching every init entry + translating back on submit — a medium-risk
refactor that delivers no user-visible benefit beyond the styling
change itself.

Select.tsx:
- `select select-bordered select-xs` → plain <select> with shadcn
  token classes (border-input, bg-background, ring-ring)
- cn() helper adopted
- Label wrapper: daisyUI `form-control` / `label-text` → plain
  flex-col + text-muted-foreground

All callers (SidoSelect, SigunguSelect, ShelterSelect, UpkindSelect,
KindSelect) are unchanged — they still pass `register` + children
<option> elements.

- nx affected -t lint test build --exclude web-e2e green
- daisyUI plugin still present (removed in #54)

Refs #53
Closes out the #8 chain.

Bottom.tsx:
- daisyUI `btm-nav btm-nav-xs` + nested `<button><a>` rebuilt as a
  plain Tailwind fixed bottom nav: `fixed inset-x-0 bottom-0 h-12
  flex border-t border-border bg-background`. Each item is a real
  <button type="button"> (no anchor-in-button nesting) with
  aria-label per item, active state swaps text-primary vs
  text-muted-foreground.
- React-icons kept; layout fires router.push as before.

Tailwind config:
- `plugins: [require('tailwindcss-animate'), require('daisyui')]`
  → `plugins: [require('tailwindcss-animate')]`. CSS variables still
  drive all color tokens (set up in #48).

Dependency purge:
- daisyui
- @mui/joy, @mui/icons-material, @mui/x-date-pickers — all zero
  imports in apps/web/src (grep-verified)
- @emotion/react, @emotion/styled — bundled only because MUI pulled
  them; framer-motion has its own emotion vendoring so dropping
  these is safe

Final audits:
- nx affected -t lint test build --exclude web-e2e green
- rg "bg-neutral(?![-\\w])|text-neutral-content|bg-base-\\d|
  text-base-content|btm-nav|navbar|btn-ghost|btn-link|btn-primary|
  btn-neutral|card-body|card-title|select-bordered|menu-|daisyui"
  apps/web → zero matches outside .next/
- package.json contains no daisyui/@mui/@emotion entries

Refs #54
@vercel

vercel Bot commented Apr 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
animal-project Error Error Apr 13, 2026 8:50am

@sourcery-ai

sourcery-ai Bot commented Apr 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

Migrates the web app’s UI away from daisyUI/MUI to a shadcn-style Tailwind + Radix component stack, rebuilding the bottom navigation and key search/home components while wiring Tailwind to design tokens and purging legacy dependencies.

Sequence diagram for navigation via rebuilt Bottom nav

sequenceDiagram
  actor User
  participant Bottom as Bottom_nav
  participant Router as Next_router
  participant Page as Next_page

  User->>Bottom: tap_button(path)
  Bottom->>Router: push(path)
  Router-->>Page: render_new_route
  Page-->>User: updated_screen
Loading

Class diagram for new shadcn-style UI primitives and utilities

classDiagram
  direction LR

  class Utils {
    +cn(inputs ClassValue[]) string
  }

  class Button {
    +buttonVariants
    +asChild boolean
    +variant
    +size
  }

  class Card {
  }
  class CardHeader {
  }
  class CardTitle {
  }
  class CardDescription {
  }
  class CardContent {
  }
  class CardFooter {
  }

  class Avatar {
  }
  class AvatarImage {
  }
  class AvatarFallback {
  }

  class Progress {
    +value number
  }

  class Skeleton {
  }

  Utils <.. Button : uses cn
  Utils <.. Card : uses cn
  Utils <.. CardHeader : uses cn
  Utils <.. CardTitle : uses cn
  Utils <.. CardDescription : uses cn
  Utils <.. CardContent : uses cn
  Utils <.. CardFooter : uses cn
  Utils <.. Avatar : uses cn
  Utils <.. AvatarImage : uses cn
  Utils <.. AvatarFallback : uses cn
  Utils <.. Progress : uses cn
  Utils <.. Skeleton : uses cn

  Button ..> Progress : shares_tailwind_tokens
  Button ..> Card : shares_tailwind_tokens
  Button ..> Avatar : shares_tailwind_tokens
  Button ..> Skeleton : shares_tailwind_tokens
Loading

Class diagram for updated page-level components using new UI primitives

classDiagram
  direction LR

  class Bottom {
    -pathname string
    -router
    -barItem
  }

  class Header {
  }

  class CountList {
    -items Sido[]
    -query
  }

  class AnimalCard {
    -item AnimalInfo
    -like boolean
    -toggleLike()
  }

  class Select {
    -labelName string
    -children ReactNode
    -register UseFormRegister
    -name string
  }

  class SearchView {
    -animalInfoRequest AnimalInfoRequestType
    -fetchNextPage()
  }

  class Button {
  }

  class Card {
  }

  class CardContent {
  }

  class Avatar {
  }

  class AvatarImage {
  }

  class Progress {
  }

  class Skeleton {
  }

  Bottom ..> Button : uses_variant_and_cn
  Header ..> Button : uses_ghost_variant

  CountList ..> Avatar : renders_logo
  CountList ..> AvatarImage : renders_logo_image
  CountList ..> Skeleton : loading_placeholders

  AnimalCard ..> Card : wraps_content
  AnimalCard ..> CardContent : body_layout

  Select ..> Button : not_used
  Select ..> Skeleton : not_used

  SearchView ..> Progress : loader_indicator
Loading

File-Level Changes

Change Details Files
Rebuild bottom navigation with accessible Tailwind implementation and remove daisyUI usage.
  • Replace daisyUI btm-nav markup with a fixed bottom using Tailwind classes and design-token colors.
  • Use real items with aria-labels instead of nested anchor-in-button and compute active state from pathname.
  • Leverage cn utility for conditional classes and remove Bottom export from barrel file, deleting unused sidebar component.
apps/web/src/new-component/bottom.tsx
apps/web/src/new-component/index.ts
apps/web/src/new-component/sidebar.tsx
Introduce shadcn-style UI primitives (Button, Card, Avatar, Progress, Skeleton) and use them in place of daisyUI components.
  • Add reusable Button, Card, Avatar, Progress, and Skeleton components based on Radix UI and class-variance-authority utilities.
  • Refactor Header, home contents, animal search cards, select inputs, search form submit button, infinite loader, and count list to use new primitives instead of daisyUI classes.
  • Enable client components where needed (e.g., AnimalCard, CountList) to support hooks and interactive UI.
apps/web/src/new-component/ui/button.tsx
apps/web/src/new-component/ui/card.tsx
apps/web/src/new-component/ui/avatar.tsx
apps/web/src/new-component/ui/progress.tsx
apps/web/src/new-component/ui/skeleton.tsx
apps/web/src/new-component/header.tsx
apps/web/src/new-site/home/Contents.tsx
apps/web/src/new-site/search/card/AnimalCard.tsx
apps/web/src/new-site/search/select/Select.tsx
apps/web/src/new-site/search/Form.tsx
apps/web/src/new-site/search/SearchView.tsx
apps/web/src/new-site/home/Count.tsx
Wire Tailwind theme to CSS custom properties and configure dark mode + utilities helper.
  • Define CSS variables for semantic colors and radius on :root and .dark in globals.css.
  • Extend Tailwind theme colors and borderRadius to use the CSS variables and enable class-based darkMode.
  • Introduce a cn utility using clsx and tailwind-merge to simplify composing Tailwind class names.
apps/web/app/globals.css
apps/web/tailwind.config.js
apps/web/src/lib/utils.ts
Purge daisyUI and MUI/Emotion dependencies and add Radix/CVA/tailwind utilities.
  • Remove daisyui plugin from Tailwind configuration and stop using daisyUI-specific class names across components.
  • Drop @mui/* and @emotion/* packages plus daisyui from package.json devDependencies.
  • Add Radix UI (avatar, progress, slot), class-variance-authority, clsx, tailwind-merge, tailwindcss-animate, and lucide-react to support new UI layer and update package-lock accordingly.
apps/web/tailwind.config.js
package.json
package-lock.json
Adjust project configuration and analytics settings.
  • Enable Nx analytics in nx.json configuration.
nx.json

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@nx-cloud

nx-cloud Bot commented Apr 13, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit d8116be

Command Status Duration Result
nx build web ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-13 08:52:01 UTC

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In the new CardTitle and CardDescription components, the forwarded ref/prop types (HTMLHeadingElement / HTMLParagraphElement) don't match the actual rendered element (div), which can cause typing and ref issues; either change the element to hX/p tags or align the generic types with HTMLDivElement.
  • Several lists still use uuidv4() for React keys (Bottom nav items, CountList), which regenerates keys on every render; consider using a stable property from the data (e.g., path or orgCd) as the key to avoid unnecessary remounting.
  • The new Radix Progress-based loader in SearchView is always rendered with value undefined (falling back to 0), so the indicator remains fully translated offscreen; if you intend an indeterminate loader, consider adding a CSS animation or passing a mid-range value to make the progress bar visibly active.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the new `CardTitle` and `CardDescription` components, the forwarded ref/prop types (`HTMLHeadingElement` / `HTMLParagraphElement`) don't match the actual rendered element (`div`), which can cause typing and ref issues; either change the element to `hX`/`p` tags or align the generic types with `HTMLDivElement`.
- Several lists still use `uuidv4()` for React keys (`Bottom` nav items, `CountList`), which regenerates keys on every render; consider using a stable property from the data (e.g., `path` or `orgCd`) as the key to avoid unnecessary remounting.
- The new Radix `Progress`-based loader in `SearchView` is always rendered with `value` undefined (falling back to 0), so the indicator remains fully translated offscreen; if you intend an indeterminate loader, consider adding a CSS animation or passing a mid-range value to make the progress bar visibly active.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant